//
// Created by QU on 24-6-18.
//

#include <iostream>
#include <string>
#include <new>  // for placement new

// union 一种节省内存的类
// union本身没有类似RTTI的类型识别机制, 一般我们需要手动建立一个变量标记他的类型进行管理

// 枚举类型，用于标记当前活跃的成员
enum class Type {
    None,
    Int,
    Double,
    String
};

class MyUnion {
private:
    // 使用 union 存储不同的类型
    union {
        int i;
        double d;
        std::string s;
    };
    Type type;  // 记录当前活跃成员的类型

public:
    // 默认构造函数，初始化 type 为 None
    MyUnion() : type(Type::None) {}

    // 析构函数，销毁当前活跃成员
    ~MyUnion() { reset(); }

    // 复制赋值运算符
    MyUnion& operator=(const MyUnion& other) {
        if (this != &other) {
            reset();
            switch (other.type) {
                case Type::Int:
                    i = other.i;
                    type = Type::Int;
                    break;
                case Type::Double:
                    d = other.d;
                    type = Type::Double;
                    break;
                case Type::String:
                    new (&s) std::string(other.s);
                    type = Type::String;
                    break;
                case Type::None:
                    type = Type::None;
                    break;
            }
        }
        return *this;
    }

    // 移动赋值运算符
    MyUnion& operator=(MyUnion&& other) noexcept {
        if (this != &other) {
            reset();
            switch (other.type) {
                case Type::Int:
                    i = other.i;
                    type = Type::Int;
                    break;
                case Type::Double:
                    d = other.d;
                    type = Type::Double;
                    break;
                case Type::String:
                    new (&s) std::string(std::move(other.s));
                    type = Type::String;
                    break;
                case Type::None:
                    type = Type::None;
                    break;
            }
            other.reset();
        }
        return *this;
    }

    // 设置 int 类型的成员
    void setInt(int val) {
        reset();
        i = val;
        type = Type::Int;
    }

    // 设置 double 类型的成员
    void setDouble(double val) {
        reset();
        d = val;
        type = Type::Double;
    }

    // 设置 string 类型的成员
    void setString(const std::string& val) {
        reset();
        new (&s) std::string(val);
        type = Type::String;
    }

    // 打印当前活跃成员的值
    void print() const {
        switch (type) {
            case Type::Int:
                std::cout << i << std::endl;
                break;
            case Type::Double:
                std::cout << d << std::endl;
                break;
            case Type::String:
                std::cout << s << std::endl;
                break;
            case Type::None:
                std::cout << "None" << std::endl;
                break;
        }
    }

private:
    // 销毁当前活跃成员并将 type 设置为 None
    void reset() {
        if (type == Type::String) {
            s.~std::string();
        }
        type = Type::None;
    }
};

int main() {
    MyUnion u1;
    u1.setString("Hello, World!");
    u1.print();

    MyUnion u2;
    u2 = u1;
    u2.print();

    u2.setInt(42);
    u2.print();

    MyUnion u3;
    u3 = std::move(u2);
    u3.print();
    u2.print();  // 应该是 "None" 因为 u2 已经被移走

    return 0;
}


//在类中使用union确实会增加一些复杂性，尤其是当union包含非POD(plain of DATA)类型时。
//如果不正确地管理这些类型的构造和析构，可能会导致未定义行为。因此，在现代C++中，我们通常有更好的替代方案，比如std::variant。

//std::variant的优势
//        std::variant是C++17引入的一个类型安全的联合类型，它提供了许多union所不具备的安全性和易用性：

//类型安全：std::variant知道当前保存的类型，并会确保在访问前进行类型检查。
//自动管理资源：std::variant会自动调用构造函数和析构函数，减少手动管理的复杂性。
//标准库支持：std::variant是标准库的一部分，有很多实用的辅助函数和特性，如std::visit。
//        以下是一个使用std::variant的示例代码，与之前的union示例功能相同：

/*

#include <iostream>
#include <variant>
#include <string>

class MyClass {
public:
    std::variant<int, double, std::string> data;

    void setInt(int val) {
        data = val;
    }

    void setDouble(double val) {
        data = val;
    }

    void setString(const std::string& val) {
        data = val;
    }

    void print() const {
        std::visit([](const auto& value) {
            std::cout << value << std::endl;
        }, data);
    }
};

int main() {
    MyClass obj;
    obj.setString("Hello, World!");
    obj.print();

    obj.setInt(42);
    obj.print();

    obj.setDouble(3.14);
    obj.print();

    return 0;
}

 */
//解释
//        类型安全：std::variant<int, double, std::string>定义了一个可以存储int、double或std::string的变体。
//简化接口：通过赋值运算符，std::variant自动管理成员的构造和析构。
// 访问和打印：std::visit提供了一种安全且方便的方式来访问和处理variant中存储的值。
// 何时使用union
//        尽管std::variant提供了许多优点，但在某些性能关键的场景下，union仍然有其用武之地。
//        例如，如果你需要手动优化内存布局或在性能上有极高要求，且可以确保正确地管理构造和析构，那么union可能是合适的选择。